 /*
 Copyright (C) 2024 HiHope Open Source Organization .
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */

#include <stdio.h>    
#include <stdlib.h>   
#include <string.h>    
#include "ohos_init.h" 
#include "cmsis_os2.h" 
#include "unistd.h" 

#include "MQTTClient.h"     // MQTTClient-C库接口文件
#include "mqtt_ohos.h"      // OHOS适配接口文件

#include "iot_gpio.h"   
#include "iot_gpio_ex.h"
#include "iot_errno.h" 

#include "aht20.h"     
#include "cJSON.h"

#define AHT20_BAUDRATE 400000

#define AHT20_I2C_IDX 1

//要连接热点的名称，根据实际情况修改
#define SSID "harmony-iot"

//要连接热点的密码，根据实际情况修改
#define PSK "123456789"



// MQTT服务器端口,请根据实际情况修改
#define MQTT_SERVER_PORT 1883   
// MQTT服务器IP地址（默认是电脑的地址）,请根据实际情况修改
//连接物联网云平台地址
#define HOST_ADDR "xx"
//连接物联网云设备ID
#define DEVICE_ID "xx"
//填入在通鸿物联网平台设置的用户名
#define USERNAME    "xx"
//连接物联网云密码
#define DEVICE_PWD  "xx"//填入在通鸿物联网平台设置的密码
//连接物联网云设备MQTT的订阅和上报Topic
#define PUBLISH_TOPIC "$oc/devices/"USERNAME"/sys/properties/report"
#define SUBCRIB_TOPIC "$oc/devices/"USERNAME"/sys/commands/#" ///request_id={request_id}"
#define RESPONSE_TOPIC "$oc/devices/"USERNAME"/sys/commands/response" ///request_id={request_id}"
#define SERVICE_ID  "Smart_fan"//设置产品服务ID
//设置设备状态指令
#define OFF     "OFF"
#define ON      "ON"

#define LED_TASK_GPIO1 10
// MQTT客户端
static MQTTClient client = {0};

// MQTT网络连接
static Network network = {0};

// 发送和接收的数据缓冲区
static unsigned char sendbuf[1000], readbuf[1000];

//MQTT消息
MQTTMessage message;

//温湿度数据
float temperature;
float humidity;
//设备驱动状态
int led_sta=0,fan_sta=0;
//有效数据
char payload[100] = {0}; 
//接收到控制指令返回上报
void messageCmdback(char *request_id)
{
    int rc;
    char rsptopic[128]={0};
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,request_id);
    printf("rsptopic = %s\n",rsptopic);
    MQTTMessage message;
    char payload[300];
    message.qos = 0;
    message.retained = 0;
    message.payload = payload;
    sprintf(payload, "{ \
    \"result_code\": 0, \
    \"response_name\": \"COMMAND_RESPONSE\", \
    \"paras\": { \
        \"result\": \"success\" \
    } \
    }" );
    message.payloadlen = strlen(payload);
    //publish the msg to responese topic
    if ((rc = MQTTPublish(&client, rsptopic, &message)) != 0) {
        printf("Return code from MQTT publish is %d\n", rc);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
    }
}
//接收到控制指令进行对应处理控制
void messageArrived(MessageData* data)
{
    int rc;
    printf("Message arrived on topic %.*s: %.*s\n", data->topicName->lenstring.len, data->topicName->lenstring.data,
           data->message->payloadlen, data->message->payload);
   //get request id
    char *request_id_idx=NULL;
    char request_id[40]={0};
    request_id_idx = strstr(data->topicName->lenstring.data,"request_id=");
    strncpy(request_id,request_id_idx+11,36);
    printf("request_id = %s\n",request_id);
    //create response topic
    char rsptopic[128]={0};
    sprintf(rsptopic,"%s/request_id=%s",RESPONSE_TOPIC,request_id);
    printf("rsptopic = %s\n",rsptopic);
    printf("msg=%s\n",data->message->payload);

    cJSON *root = cJSON_ParseWithLength( data->message->payload, data->message->payloadlen);
    if(root != NULL){
        cJSON *cmd_name = cJSON_GetObjectItem(root,"command_name");
        if(cmd_name != NULL){
            char *cmd_name_str = cJSON_GetStringValue(cmd_name);
            if(strcmp(cmd_name_str,"fan_control") == 0){
                cJSON *para_obj = cJSON_GetObjectItem(root,"paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj,"fan");
                char *data = NULL;
                 data = cJSON_GetStringValue(status_obj);
                 if(data != NULL){
                    if(strcmp(data,OFF) == 0)
                    {
                        IoTGpioSetOutputVal(LED_TASK_GPIO1,0);
                        fan_sta = 0;
                    }
                    else{
                        IoTGpioSetOutputVal(LED_TASK_GPIO1,1);
                        fan_sta = 1;
                    }
                    printf("fan_sta = %d\n",fan_sta);
                }
            }else if(strcmp(cmd_name_str,"led_control") == 0){
                cJSON *para_obj = cJSON_GetObjectItem(root,"paras");
                cJSON *status_obj = cJSON_GetObjectItem(para_obj,"led");
                char *data = NULL;
                 data = cJSON_GetStringValue(status_obj);
                 if(data != NULL){
                    if(strcmp(data,OFF) == 0)
                    {
                        IoTGpioSetOutputVal(LED_TASK_GPIO1,0);
                        led_sta = 0;
                    }
                    else{
                        IoTGpioSetOutputVal(LED_TASK_GPIO1,1);
                        led_sta = 1;
                    }
                    printf("led_sta = %d\n",led_sta);
                }
            }
            messageCmdback(request_id);
         
        }
        cJSON_Delete(root);
    }
}                            
//初始化传感器
static void InitTempHumiSensor()
{

    // 初始化GPIO
    IoTGpioInit(1); 

    // 设置GPIO-15引脚功能为I2C1_SDA
    IoSetFunc(IOT_IO_NAME_GPIO_15, IOT_IO_FUNC_GPIO_15_I2C1_SDA);
    // 设置GPIO-16引脚功能为I2C1_SCL
    IoSetFunc(IOT_IO_NAME_GPIO_16, IOT_IO_FUNC_GPIO_16_I2C1_SCL);

    // 初始化I2C1
    IoTI2cInit(AHT20_I2C_IDX, AHT20_BAUDRATE);


    // 校准AHT20,需要等待一段时间
    while (IOT_SUCCESS != AHT20_Calibrate())
    {
        printf("AHT20 sensor init failed!\r\n");  
    }
}
//获取温湿度
static uint16_t GetTempHumi(float *temperature, float *humidity){
    char tempData[15] = {0};
    char humiData[15] = {0};
    // 启动测量
    if (AHT20_StartMeasure() != IOT_SUCCESS)
    {
        printf("measure failed!\r\n");
        return IOT_FAILURE;
    }
    //获取测量结果
    if (AHT20_GetMeasureResult(temperature, humidity) != IOT_SUCCESS)
    {
        printf("get data failed!\r\n");
        return IOT_FAILURE;
    }
    //打印温湿度数据
    sprintf(tempData, "%.2f", *temperature);
    sprintf(humiData, "%.2f", *humidity);
    printf("temperature: %s, humidity: %s\r\n", tempData, humiData);

    return IOT_SUCCESS;
}

static void mqttDemoTask(void *arg)
{
    (void)arg;
    int ret;
    //初始化led2
    IoTGpioInit(LED_TASK_GPIO1);
    IoTGpioSetDir(LED_TASK_GPIO1,IOT_GPIO_DIR_OUT);
    InitTempHumiSensor();
    // 连接到热点
    if (ConnectToHotspot(SSID, PSK) != 0)
    {
        // 连接到热点失败
        printf("Connect to AP failed\r\n"); 
        return;
    }
    printf("Connect to AP ok\r\n"); 
    // 等待TCP连接完成
    osDelay(100);
    printf("MQTTClientstart  ...\n");
begin:
    //初始化MQTT相关的参数和回调
    NetworkInit(&network);
    
    //配置MQTT连接数据
    NetworkConnect(&network, HOST_ADDR, MQTT_SERVER_PORT);
    printf("MQTTClientInit  ...\n");
    // 初始化MQTT客户端
    MQTTClientInit(&client, &network, 200, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf));

    printf("Connect to mqtt link\r\n"); 
    // 初始化MQTT连接信息
    MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
    //配置物联网云平台MQTT设备ID
    MQTTString clientId = MQTTString_initializer;
    clientId.cstring = DEVICE_ID; 
    //配置物联网云平台MQTT用户名
    MQTTString userName = MQTTString_initializer;
    userName.cstring = USERNAME; 
    //配置物联网云平台MQTT用户密码
    MQTTString password = MQTTString_initializer;
    password.cstring = DEVICE_PWD; 
    
    connectData.clientID = clientId;
    connectData.username = userName;
    connectData.password = password;

    /* 设置MQTT版本*/
    // 3 = 3.1
    // 4 = 3.1.1
    connectData.MQTTVersion = 4;


    // 发送MQTT连接包
    if ((ret = MQTTConnect(&client, &connectData)) != 0)
    {
        // 连接失败
        printf("Connect MQTT Broker failed!,ret = %d\r\n",ret);
        osDelay(200);
        NetworkDisconnect(&network);
        MQTTDisconnect(&client);
        goto begin;
        return;
    }else{
       // 成功连接到MQTT服务器
        printf("MQTT Connected!\r\n");
    }

   

    //配置物联网云平台MQTT订阅对应指令Topic
    printf("MQTTSubscribe  ...\n");
    int rc = MQTTSubscribe(&client, SUBCRIB_TOPIC, 0, messageArrived);
    if (rc != 0) {
        printf("MQTTSubscribe: %d\n", rc);
        osDelay(200);
        goto begin;
    }
    //发布的主题
    char *topic = "device_sensor_data";         
    int c = 1;
    while (c)
    {
      uint16_t ret = GetTempHumi(&temperature, &humidity);
      if(ret == 0){
            MQTTMessage message;
            // char *publishtopic="$oc/devices/test_fan_1/sys/properties/report";
            char payload[1000]={0};
            char str[20]= {0};
            cJSON *root = cJSON_CreateObject();
            if(root != NULL){
                cJSON *serv_arr = cJSON_AddArrayToObject(root, "services");
                cJSON *arr_item =  cJSON_CreateObject();
                cJSON_AddStringToObject(arr_item,"service_id",SERVICE_ID);
                cJSON *pro_obj = cJSON_CreateObject();
                cJSON_AddItemToObject(arr_item,"properties",pro_obj);
                if(led_sta == 0){
                    cJSON_AddStringToObject(pro_obj,"LightStatus",OFF);
                }
                else{
                    cJSON_AddStringToObject(pro_obj,"LightStatus",ON);
                }
                if(fan_sta == 0){
                    cJSON_AddStringToObject(pro_obj,"MotorStatus",OFF);
                }
                else{
                    cJSON_AddStringToObject(pro_obj,"MotorStatus",ON);
                }
                sprintf(str, "%5.2f℃", temperature);
                cJSON_AddStringToObject(pro_obj, "Temperature", str);
                // 湿度
                sprintf(str, "%5.2f%%", humidity);
                cJSON_AddStringToObject(pro_obj, "Humidity", str);
                cJSON_AddItemToArray(serv_arr,arr_item);
                char *palyload_str = cJSON_PrintUnformatted(root);
                strcpy(payload,palyload_str);
                cJSON_free(palyload_str);
                cJSON_Delete(root);
            }
            message.qos = 0;
            message.retained = 0;
            message.payload = payload;
            message.payloadlen = strlen(payload);
            if ((rc = MQTTPublish(&client, PUBLISH_TOPIC, &message)) != 0) {
                printf("Return code from MQTT publish is %d\n", rc);
                NetworkDisconnect(&network);
                MQTTDisconnect(&client);
                goto begin;
            }else{
                printf("mqtt publish success:%s\n",payload);
            }
            MQTTYield(&client, 500);
        }    
       
        osDelay(100);                                       
    }
    
    
}

// 入口函数
static void mqttDemoEntry(void)
{
    // 定义线程属性
    osThreadAttr_t attr;
    attr.name = "mqttDemoTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    // 创建线程
    if (osThreadNew(mqttDemoTask, NULL, &attr) == NULL)
    {
        printf("[mqttDemoEntry] Falied to create mqttDemoTask!\n");
    }
}

// 运行入口函数
APP_FEATURE_INIT(mqttDemoEntry);
